// Initial File - Paul Jack

#include <QByteArray>
#include <QString>
#include <status_strings.h>

#include "usbdevice.h"
#include "usbconstants.h"




/*!
 * UsbDevice::UsbDevice 
 *
 * Description: 
 *
 * @param cmdPipe is of type int 
 * @param respPipe is of type int 
 * @param bulkPipe is of type int 
 * @param writeTimeout is of type int 
 * @param readTimeout is of type int 
 * @param bulkTimeout is of type int 
 * @param crLf is of type bool 
 *
 * @returns None
 */
UsbDevice::UsbDevice(int cmdPipe, int respPipe, int bulkPipe, int writeTimeout, int readTimeout, int bulkTimeout, bool crLf):
CommDevice(),
mCmdPipe(cmdPipe),
mRespPipe(respPipe),
mBulkPipe(bulkPipe),
mWriteTimeout(writeTimeout),
mReadTimeout(readTimeout),
mBulkTimeout(bulkTimeout),
mRemoveCrLf(true),
mDisplayMessages(crLf)
{
    
    mBuffer.resize (R_USB_MAX_TRANSFER + 1);

    mConnected = false;


    mWriteErrorCode = WD_STATUS_SUCCESS;
    mReadBulkErrorCode = WD_STATUS_SUCCESS;
    mReadErrorCode = WD_STATUS_SUCCESS;
    mhDevice = NULL;
}




/*!
 * UsbDevice::write 
 *
 * Description: 
 *
 * @param &str is of type const QByteArray 
 *
 * @returns bool 
 */
bool UsbDevice::write(const QByteArray &str)
{
    bool bResult = true;

    if(!str.count())
    {
        return bResult;
    }

    QByteArray tmp = str + "\n";
    quint8 setupPacket[8];
    ulong bytesTransferred;
    BZERO(setupPacket);

    if(mhDevice == NULL)
    {
        return false;
    }

    if(mDisplayMessages)
    {
        qDebug("=> %s", tmp.data());
    }

    quint32 mWriteErrorCode = WDU_Transfer(mhDevice,  // Handle to the USB device.
        mCmdPipe,           // The pipe we want to write to.
        false,              // true for read, false for write.
        0,                  // This means no isoch transfers?
        tmp.data(),         // Address of the data buffer
        tmp.length(),       // Number of bytes to transfer
        &bytesTransferred,  // Number of bytes actually transfered
        setupPacket,        // An 8-Byte packet to transfer to the control
                            // pipe. I don't know what is does. We set it
        mWriteTimeout);     // Timeout interval in millisecond

    if(mWriteErrorCode)
    {
        if(mDisplayMessages)
        {
            qDebug( "UsbDevice::write: WDU_Transfer() failed: error 0x%lx "
                    "(\"%s\")", mWriteErrorCode, Stat2Str( mWriteErrorCode ) );
        }
        
        bResult = false;
    }

    return bResult;
}



/*!
 * UsbDevice::readBulk 
 *
 * Description: 
 *
 * @param &array is of type QByteArray 
 *
 * @returns bool 
 */
bool UsbDevice::readBulk(QByteArray &array)
{
    bool result = false;
    DWORD bytesTransferred;


    if(mhDevice == NULL)
    {
        return false;
    }

    DWORD  mReadBulkErrorCode = WDU_TransferBulk(mhDevice,
                                    // Handle to the USB device.
            mBulkPipe,              // The pipe we want to read from
            true,                   // true for read, false for write.
            0,                      // This means no isoch transfers?
            array.data(),           // Address of the data buffer
            array.size(),           // Number of bytes to transfer
            &bytesTransferred,      // Number of bytes actually transfered
            mBulkTimeout);          // Wait

    if(mReadBulkErrorCode != WD_STATUS_SUCCESS)
    {
        if(mDisplayMessages)
        {
            qDebug("AsyncMgr::readBulk: WDU_TransferBulk() failed: error 0x%lx "
               "(\"%s\")", mReadBulkErrorCode, Stat2Str(mReadBulkErrorCode));
        }

        if(mReadBulkErrorCode == WD_TIME_OUT_EXPIRED)
        {
            // result = false;
            result = true;
        }
        else
        {
            result = false;
        }
    }
    else
    {

        static int packetCount = 1;
        //qDebug("packetNumber: %d", packetCount++);
        if(bytesTransferred < array.size())
        {
            array.resize(bytesTransferred);
        }
        result = true;
    }

    return result;
}



/*!
 * UsbDevice::read 
 *
 * Description: 
 *
 * @param &str is of type QByteArray 
 *
 * @returns bool 
 */
bool UsbDevice::read(QByteArray &str)
{
    bool result = false;

    BYTE setupPacket[8];
    DWORD bytesTransferred;
    BZERO(setupPacket);

    if(mhDevice == NULL)
    {
        return false;
    }

    UINT32 mReadErrorCode = WDU_Transfer(mhDevice,  // Handle to the USB device.
            mRespPipe,          // The pipe we want to read from
            true,               // true for read, false for write.
            0,                  // This means no isoch transfers?
            mBuffer.data(),     // Address of the data buffer
            mBuffer.size() - 1, // Number of bytes to transfer
            &bytesTransferred,  // Number of bytes actually transfered
            setupPacket,        // An 8-Byte packet to transfer to the control
                                // pipe. I don't know what is does. We set it
                                // to zeros.
            //0 );              // Wait indefinitely.
            mReadTimeout);

    if((mReadErrorCode != WD_STATUS_SUCCESS) && (mReadErrorCode != WD_TIME_OUT_EXPIRED))
    {

        if(mDisplayMessages)
        {
             qDebug( "UsbDevice::read: WDU_Transfer() failed: error 0x%lx "
                 "(\"%s\")", mReadErrorCode, Stat2Str( mReadErrorCode ) );
        }

        result = false;
    }
    else
    {
        if(mReadErrorCode != WD_TIME_OUT_EXPIRED)
        {
            mBuffer.data()[bytesTransferred] = '\0';
            str = mBuffer;
            if(mRemoveCrLf)
            {
                str.replace('\n', "");
                str.replace('\r', "");
            }

            if(mDisplayMessages)
            {
                qDebug("<= %s", mBuffer.data());
            }
            
        }
        result = true;
    }

    return result;
}



/*!
 * UsbDevice::removeCrLf 
 *
 * Description: 
 *
 * @param crLf is of type bool 
 *
 * @returns void 
 */
void UsbDevice::removeCrLf(bool crLf)
{
    mRemoveCrLf = crLf;
}



/*!
 * UsbDevice::setConnected 
 *
 * Description: 
 *
 * @param state is of type bool 
 *
 * @returns void 
 */
void UsbDevice::setConnected(bool state)
{
    mConnected = state;
}




/*!
 * UsbDevice::isConnected 
 *
 * Description: 
 *
 *
 * @returns bool 
 */
bool UsbDevice::isConnected(void)
{
    return mConnected;
}





/*!
 * UsbDevice::getIdentification 
 *
 * Description: 
 *
 *
 * @returns QString 
 */
QString UsbDevice::getIdentification()
{
    return mIdentification.trimmed();
}

QString UsbDevice::getDescription()
{
    return mDescription.trimmed();
}

quint32 UsbDevice::getReadBulkErrorCode( void )
{
    quint32 status = mReadBulkErrorCode;
    mReadBulkErrorCode = WD_STATUS_SUCCESS;

    return status;
}

quint32 UsbDevice::getReadErrorCode( void )
{
    quint32 status = mReadErrorCode;
    mReadErrorCode = WD_STATUS_SUCCESS;

    return status;
}

quint32 UsbDevice::getWriteErrorCode( void )
{
    quint32 status = mWriteErrorCode;
    mWriteErrorCode = WD_STATUS_SUCCESS;

    return status;
}
